//学习 单例模式

#include <iostream>
#include <mutex>

using namespace std;

//饿汉模式
//程序启动时就创建了单例对象
class HungryMan
{
public:
    static HungryMan& getInstance()
    {
        return _hm;
    }

    int getData()
    {
        return _data;
    }

private:
    HungryMan() :_data(66)   //构造
    {
        std::cout << "单例对象(饿汉)已创建" << std::endl;
    }

    HungryMan(const HungryMan&) = delete; //拷贝构造
    ~HungryMan() {} //析构
    static HungryMan _hm;   //单例对象
private:
    int _data;  //数据
};

//类外初始化
HungryMan HungryMan::_hm;

// //懒汉模式（常规写法）
//首次调用获取单例对象函数时创建单例对象
// class LazyMan
// {
// public:
//     static LazyMan* getInstance()
//     {
//         //双检查加锁
//         if(_plm == nullptr)
//         {
//             //加锁保护
//             _mtx.lock();
//             if(_plm == nullptr)
//             {
//                 //首次调用时创建对象
//                 _plm = new LazyMan();
//             }
//             _mtx.unlock();
//         }

//         return _plm;
//     }

//     int getData()
//     {
//         return _data;
//     }

// private:
//     LazyMan()   //构造
//         :_data(66) 
//     {
//         std::cout << "单例对象(懒汉)已创建" << std::endl;
//     }

//     LazyMan(const LazyMan&) = delete;  //拷贝构造
//     ~LazyMan() {}   //析构
//     static LazyMan *_plm;  //指向单例对象的指针
//     static std::mutex _mtx;    //保护单例对象首次创建的锁
// private:
//     int _data;
// };

// LazyMan* LazyMan::_plm = nullptr;
// std::mutex LazyMan::_mtx;

//懒汉模式（特殊写法）
//注意：创建静态变量仅在 C++11 之后保证是线程安全的
class LazyMan
{
public:
    static LazyMan& getInstance()
    {
        static LazyMan _lm;  //静态的单例对象
        return _lm;
    }

    int getData()
    {
        return _data;
    }

private:
    LazyMan()   //构造
        :_data(66) 
    {
        std::cout << "单例对象(懒汉)已创建" << std::endl;
    }

    LazyMan(const LazyMan&) = delete;  //拷贝构造
    ~LazyMan() {}   //析构
private:
    int _data;
};


int main()
{
    // cout << HungryMan::getInstance().getData() << endl;
    // cout << LazyMan::getInstance()->getData() << endl;
    cout << LazyMan::getInstance().getData() << endl;
    return 0;
}